﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Windows;
using GTasksPlus.Model;
using Newtonsoft.Json.Linq;
using RestSharp;

namespace GTasksPlus.Code
{
    public class TaskListHelper
    {
        #region Create List

        public static void AddTaskList(TaskListItem taskListItem, Action<bool> response)
        {
            OAuthHelper.RefreshTokenCode(p => RetryAddTaskList(new List<object>{taskListItem,response}));
        }

        private static void RetryAddTaskList(IList<object> obj)
        {
            const string message = "Some error while trying to create a Tasks List.";
            var client = new RestClient { Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(GTasksSettings.AccessToken), Timeout = GTasksSettings.RequestTimeout };
            var request = new RestRequest(Method.POST)
            {
                RequestFormat = DataFormat.Json,
                Resource = "https://www.googleapis.com/tasks/v1/users/@me/lists"
            };
            var ignored = "{title:\"" + ((TaskListItem)obj[0]).title + "\"}";
            request.AddParameter("application/json", ignored, ParameterType.RequestBody);
            client.ExecuteAsync(request, response =>
            {
                try
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        var callback = obj[1] as Action<bool>;
                        if (callback != null) callback(true);
                    }
                    else
                    {
                         MessageBox.Show(message);
                    }
                }
                catch (Exception e)
                {
                    MessageBox.Show(message+"\n\n" + e.Message);
                }
            });
        }

        #endregion

        #region Get List

        public static void GetTaskList(Action<ObservableCollection<TaskListItem>> callback)
        {
            OAuthHelper.RefreshTokenCode(p => RetryGetTaskList(new List<object> { callback }));
        }

        private static void RetryGetTaskList(IList<object> obj)
        {
            var tasks = new ObservableCollection<TaskListItem>();
            const string message = "Some error while trying to retrieve the Task List.";
            var client = new RestClient { Timeout = GTasksSettings.RequestTimeout};
            var request = new RestRequest(Method.GET)
                              {
                                  Resource =
                                      "https://www.googleapis.com/tasks/v1/users/@me/lists?access_token=" +
                                      GTasksSettings.AccessToken
                              };
            client.ExecuteAsync(request, response =>
            {
                try
                {
                    var o = JObject.Parse(response.Content);
                    var lists =
                        o["items"].Select(
                            m =>
                            new TaskListItem((string)m.SelectToken("title"), (string)m.SelectToken("id"),
                                             (string)m.SelectToken("kind"), (string)m.SelectToken("selfLink"))).ToList
                            ();
                    tasks.Clear();
                    foreach (var taskListItem in lists)
                    {
                        tasks.Add(taskListItem);
                    }
                    var list = obj[0] as Action<ObservableCollection<TaskListItem>>;
                    if (list != null) list(tasks);
                }
                catch (Exception e)
                {
                    MessageBox.Show(message + "\n\n" + e.Message);
                }
            });
        }

        #endregion

        #region Delete List

        public static void DeleteList(TaskListItem taskListItem, Action<bool> response)
        {
            OAuthHelper.RefreshTokenCode(p=>RetryDeleteList(new List<object>{taskListItem,response}));
        }

        private static void RetryDeleteList(IList<object> obj)
        {
            const string message = "Some error while trying to delete the Tasks List.";
            var client = new RestClient { Authenticator = new OAuth2UriQueryParameterAuthenticator(GTasksSettings.AccessToken), BaseUrl = ((TaskListItem)obj[0]).selfLink, Timeout = GTasksSettings.RequestTimeout };
            var request = new RestRequest(Method.DELETE);
            client.ExecuteAsync(request, response =>
            {
                try
                {
                    if(response.StatusCode == HttpStatusCode.NoContent)
                    {
                        var callback = obj[1] as Action<bool>;
                        if (callback != null) callback(true);
                    }
                    else
                        MessageBox.Show(message);
                }
                catch (Exception e)
                {
                    MessageBox.Show(message+"\n\n" + e.Message);
                }
            });
        }

        #endregion

        #region Update List

        public static void UpdateList(TaskListItem taskListItem, Action<bool> response)
        {
            OAuthHelper.RefreshTokenCode(p => RetryUpdateList(new List<object> { taskListItem, response }));
        }

        private static void RetryUpdateList(IList<object> obj)
        {
            const string message = "Some error while trying to update the Tasks List.";
            var client = new RestClient { Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator(GTasksSettings.AccessToken), Timeout = GTasksSettings.RequestTimeout };
            var request = new RestRequest(Method.PUT)
            {
                RequestFormat = DataFormat.Json,
                Resource = ((TaskListItem)obj[0]).selfLink
            };
            request.AddBody(obj[0]);
            client.ExecuteAsync(request, response =>
            {
                try
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        var callback = obj[1] as Action<bool>;
                        if (callback != null) callback(true);
                    }
                    else
                        MessageBox.Show(message);
                }
                catch (Exception e)
                {
                    MessageBox.Show(message+"\n\n" + e.Message);
                }
            });
        }

        #endregion

        #region Get Task Items in a List

        public static void GetTasksForList(string id, Action<List<TaskItem>> callback)
        {
            OAuthHelper.RefreshTokenCode(p => RetryGetTasksForList(new List<object> { id, callback }));
        }

        private static void RetryGetTasksForList(IList<object> obj)
        {
            const string message = "Some error while trying to retrieve the Tasks for a List";
            var client = new RestClient { Timeout = GTasksSettings.RequestTimeout };
            var request = new RestRequest(Method.GET)
            {
                Resource =
                    "https://www.googleapis.com/tasks/v1/lists/" + obj[0] + "/tasks?access_token=" +
                    GTasksSettings.AccessToken
            };
            client.ExecuteAsync(request, response =>
            {
                try
                {
                    var o = JObject.Parse(response.Content);
                    var lists = new List<TaskItem>();
                    if (o != null && o["items"] != null)
                    {
                        lists =
                            o["items"].Select(
                                m => new TaskItem((string)m.SelectToken("id"),
                                                  (string)m.SelectToken("kind"),
                                                  ((string)m.SelectToken("title")) ==
                                                  String.Empty
                                                      ? "Empty"
                                                      : (string)
                                                        m.SelectToken("title"),
                                                  (string)m.SelectToken("notes"),
                                                  (string)m.SelectToken("parent"),
                                                  (string)
                                                  m.SelectToken("position"),
                                                  (string)m.SelectToken("updated"),
                                                  (string)m.SelectToken("due"),
                                                  (string)m.SelectToken("deleted"),
                                                  (string)m.SelectToken("hidden"),
                                                  (string)m.SelectToken("status"),
                                                  (string)
                                                  m.SelectToken("selfLink"),
                                                  (string)
                                                  m.SelectToken("completed")
                                         )).ToList();
                    }
                    var tasks = new List<TaskItem>();
                    tasks.Clear();
                    tasks.AddRange(lists);
                    var list = obj[1] as Action<List<TaskItem>>;
                    if (list != null) list(tasks);
                }
                catch (Exception e)
                {
                    MessageBox.Show(message+"\n\n" + e.Message);
                }
            });
        }

        #endregion

        #region Get Specific Task Item

        public static void GetSpecificTaskList(string id, Action<TaskListItem> callback)
        {
            OAuthHelper.RefreshTokenCode(p => RetryGetSpecificTaskList(new List<object> { id, callback }));
        }

        private static void RetryGetSpecificTaskList(IList<object> obj)
        {
            const string message = "Some error while trying to retrieve a specific task list.";
            var client = new RestClient{ Timeout = GTasksSettings.RequestTimeout };
            var request = new RestRequest(Method.GET)
            {
                Resource =
                    "https://www.googleapis.com/tasks/v1/users/@me/lists/" + obj[0] + "?access_token=" +
                    GTasksSettings.AccessToken
            };
            client.ExecuteAsync(request, response =>
            {
                try
                {
                    var o = JObject.Parse(response.Content);
                    var item =
                        new TaskListItem((string) o.SelectToken("title"), (string) o.SelectToken("id"),
                                         (string) o.SelectToken("kind"), (string) o.SelectToken("selfLink"));
                    var list = obj[1] as Action<TaskListItem>;
                    if (list != null) list(item);
                }
                catch (Exception e)
                {
                    MessageBox.Show(message +"\n\n" + e.Message);
                }
            });
        }

        #endregion
    }
}
